<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>摄像头控制面板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            background-color: #f5f5f5;
        }
        .container {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .camera-view {
            width: 100%;
            max-width: 640px;
            height: 480px;
            background-color: #000;
            margin: 20px auto;
            border-radius: 4px;
        }
        .controls {
            display: flex;
            justify-content: center;
            gap: 10px;
            margin: 20px 0;
        }
        button {
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
        }
        .start-btn {
            background-color: #4CAF50;
            color: white;
        }
        .stop-btn {
            background-color: #f44336;
            color: white;
        }
        .photo-btn {
            background-color: #2196F3;
            color: white;
        }
        .detect-btn {
            background-color: #9c27b0;
            color: white;
        }
        .detect-btn.active {
            background-color: #6a1b9a;
        }
        .switch-btn {
            background-color: #9c27b0;
            color: white;
        }
        button:hover {
            opacity: 0.9;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .status {
            text-align: center;
            margin: 10px 0;
            padding: 10px;
            border-radius: 4px;
        }
        .status.running {
            background-color: #e8f5e9;
            color: #2e7d32;
        }
        .status.stopped {
            background-color: #ffebee;
            color: #c62828;
        }
        .device-select {
            margin: 20px 0;
            text-align: center;
        }
        select {
            padding: 8px;
            font-size: 16px;
            border-radius: 4px;
        }
        .message {
            text-align: center;
            margin: 10px 0;
            padding: 10px;
            border-radius: 4px;
        }
        .message.success {
            background-color: #e8f5e9;
            color: #2e7d32;
        }
        .modal-overlay {
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }
        
        .modal-content {
            background-color: white;
            padding: 20px;
            border-radius: 8px;
            max-width: 90%;
            max-height: 90%;
            position: relative;
        }
        
        .modal-close {
            position: absolute;
            top: 10px;
            right: 10px;
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            color: #666;
        }
        
        .preview-image {
            max-width: 100%;
            max-height: 80vh;
            display: block;
            margin: 0 auto;
        }
        
        .preview-controls {
            margin-top: 15px;
            text-align: center;
        }
        
        .preview-controls button {
            margin: 0 5px;
        }
    </style>
</head>
<body>
    <div id="app" class="container">
        <h1 style="text-align: center">摄像头控制面板</h1>
        
        <div class="device-select">
            <label for="deviceSelect">选择摄像头设备：</label>
            <select id="deviceSelect" v-model="selectedDevice">
                <option value="0">默认摄像头</option>
                <option value="1">摄像头 1</option>
                <option value="2">摄像头 2</option>
            </select>
        </div>

        <div class="camera-view">
            <video 
                id="videoElement" 
                v-show="isRunning" 
                autoplay 
                playsinline 
                muted
                style="width: 100%; height: 100%; object-fit: contain;"
            ></video>
            <canvas id="photoCanvas" style="display: none;"></canvas>
            <div v-show="!isRunning" style="text-align: center; padding-top: 200px; color: #666;">
                摄像头未启动
            </div>
        </div>

        <div class="controls">
            <button @click="startCamera" class="start-btn" :disabled="isRunning">
                启动摄像头
            </button>
            <button @click="takePhoto" class="photo-btn" :disabled="!isRunning">
                拍照
            </button>
            <button @click="switchCamera" class="switch-btn" :disabled="!isRunning">
                切换摄像头
            </button>
            <button @click="stopCamera" class="stop-btn" :disabled="!isRunning">
                停止摄像头
            </button>
            <button @click="toggleDetection" :class="['detect-btn', isDetecting ? 'active' : '']">
                {{ isDetecting ? '关闭识别' : '开启识别' }}
            </button>
        </div>

        <div :class="['status', isRunning ? 'running' : 'stopped']">
            摄像头状态: {{ isRunning ? '运行中' : '已停止' }}
        </div>

        <div v-if="error" style="color: red; text-align: center; margin-top: 10px;">
            错误: {{ error }}
        </div>

        <div v-if="message" :class="['message', messageType]">
            {{ message }}
        </div>

        <!-- 预览模态框 -->
        <div v-if="showPreview" class="modal-overlay" @click.self="closePreview">
            <div class="modal-content">
                <button class="modal-close" @click="closePreview">&times;</button>
                <img :src="previewUrl" class="preview-image" alt="预览图片">
                <div class="preview-controls">
                    <button @click="openInFolder" class="photo-btn">
                        在文件夹中打开
                    </button>
                    <button @click="deletePhoto" class="stop-btn">
                        删除照片
                    </button>
                </div>
            </div>
        </div>
    </div>

    <script>
        new Vue({
            el: '#app',
            data: {
                isRunning: false,
                frameUrl: '',
                frameUpdateInterval: null,
                selectedDevice: '0',
                error: null,
                retryCount: 0,
                message: '',
                messageType: '',
                showPreview: false,
                previewUrl: '',
                currentPhotoPath: '',
                isDetecting: false,
                currentFacingMode: 'environment' // 'environment' 是后置摄像头，'user' 是前置摄像头
            },
            methods: {
                async startCamera() {
                    try {
                        this.error = null;
                        
                        // 获取video元素并确保其存在
                        const video = document.getElementById('videoElement');
                        if (!video) {
                            throw new Error('视频元素未找到');
                        }

                        // 重置视频元素
                        if (video.srcObject) {
                            const tracks = video.srcObject.getTracks();
                            tracks.forEach(track => track.stop());
                            video.srcObject = null;
                        }

                        // 检查浏览器支持
                        if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
                            throw new Error('您的浏览器不支持访问摄像头，请使用最新版本的Chrome或Firefox浏览器');
                        }

                        // 设置视频约束
                        const constraints = {
                            video: {
                                facingMode: this.currentFacingMode,
                                width: { ideal: 640 },
                                height: { ideal: 480 }
                            }
                        };

                        // 请求摄像头权限
                        const stream = await navigator.mediaDevices.getUserMedia(constraints);
                        
                        // 设置视频流
                        video.srcObject = stream;
                        
                        // 等待视频准备就绪
                        await new Promise((resolve, reject) => {
                            video.onloadedmetadata = () => resolve();
                            video.onerror = () => reject(new Error('视频加载失败'));
                        });

                        // 开始播放
                        try {
                            await video.play();
                            this.isRunning = true;
                        } catch (playError) {
                            throw new Error('无法播放视频流: ' + playError.message);
                        }

                    } catch (error) {
                        console.error('摄像头启动错误:', error);
                        this.error = `启动摄像头失败: ${error.message}`;
                        this.isRunning = false;
                        
                        // 清理资源
                        const video = document.getElementById('videoElement');
                        if (video && video.srcObject) {
                            const tracks = video.srcObject.getTracks();
                            tracks.forEach(track => track.stop());
                            video.srcObject = null;
                        }
                    }
                },

                async stopCamera() {
                    try {
                        const video = document.getElementById('videoElement');
                        if (video && video.srcObject) {
                            const tracks = video.srcObject.getTracks();
                            tracks.forEach(track => track.stop());
                            video.srcObject = null;
                        }
                        this.isRunning = false;
                        this.error = null;
                    } catch (error) {
                        console.error('停止摄像头失败:', error);
                        this.error = `停止摄像头失败: ${error.message}`;
                    }
                },

                startFrameUpdate() {
                    this.stopFrameUpdate(); // 清除可能存在的旧定时器
                    this.updateFrame(); // 立即更新一次
                    this.frameUpdateInterval = setInterval(() => {
                        this.updateFrame();
                    }, 100);
                },

                stopFrameUpdate() {
                    if (this.frameUpdateInterval) {
                        clearInterval(this.frameUpdateInterval);
                        this.frameUpdateInterval = null;
                        this.frameUrl = '';
                    }
                },

                async updateFrame() {
                    try {
                        const response = await axios.get(
                            this.isDetecting ? '/api/camera/frame/detect' : '/api/camera/frame',
                            { responseType: 'blob' }
                        );
                        if (response.status === 200 && response.data) {
                            const blob = new Blob([response.data], { type: 'image/jpeg' });
                            this.frameUrl = URL.createObjectURL(blob);
                            this.retryCount = 0;
                        }
                    } catch (error) {
                        console.error('获取视频帧失败:', error);
                        this.retryCount++;
                        if (this.retryCount > 5) {
                            this.error = '获取视频帧失败，摄像头可能已断开';
                            this.stopCamera();
                        }
                    }
                },

                handleImageError() {
                    console.error('图像加载失败');
                    this.retryCount++;
                    if (this.retryCount > 5) {
                        this.error = '图像加载失败，摄像头可能已断开';
                        this.stopCamera();
                    }
                },

                async checkStatus() {
                    try {
                        const response = await axios.get('/api/camera/status');
                        this.isRunning = response.data;
                        if (this.isRunning && !this.frameUpdateInterval) {
                            this.startFrameUpdate();
                        }
                    } catch (error) {
                        console.error('检查状态失败:', error);
                        this.error = '检查摄像头状态失败';
                    }
                },

                async takePhoto() {
                    try {
                        this.error = null;
                        const video = document.getElementById('videoElement');
                        const canvas = document.getElementById('photoCanvas');
                        
                        // 设置canvas大小与视频相同
                        canvas.width = video.videoWidth;
                        canvas.height = video.videoHeight;
                        
                        // 在canvas上绘制当前视频帧
                        const context = canvas.getContext('2d');
                        context.drawImage(video, 0, 0, canvas.width, canvas.height);
                        
                        // 将canvas内容转换为blob
                        canvas.toBlob(async (blob) => {
                            // 创建FormData对象
                            const formData = new FormData();
                            formData.append('photo', blob, 'photo.jpg');
                            
                            // 发送到服务器
                            try {
                                const response = await axios.post('/api/camera/photo/mobile', formData, {
                                    headers: {
                                        'Content-Type': 'multipart/form-data'
                                    }
                                });
                                
                                if (response.status === 200) {
                                    this.message = response.data;
                                    this.messageType = 'success';
                                    
                                    // 提取文件名并构建预览URL
                                    const fileName = response.data.split(': ')[1];
                                    this.currentPhotoPath = `C:\\Users\\15134\\Desktop\\壁纸\\${fileName}`;
                                    this.previewUrl = `/api/camera/photos/${fileName}`;
                                    this.showPreview = true;
                                }
                            } catch (error) {
                                this.error = `保存照片失败: ${error.response?.data || error.message}`;
                            }
                        }, 'image/jpeg', 0.95);
                        
                    } catch (error) {
                        this.error = `拍照失败: ${error.message}`;
                    }
                },
                
                closePreview() {
                    this.showPreview = false;
                    this.previewUrl = '';
                },
                
                openInFolder() {
                    // 通过后端API打开文件夹
                    axios.get(`/api/camera/openFolder?path=${encodeURIComponent(this.currentPhotoPath)}`)
                        .catch(error => {
                            this.error = '无法打开文件夹: ' + error.message;
                        });
                },
                
                async deletePhoto() {
                    if (!confirm('确定要删除这张照片吗？')) {
                        return;
                    }
                    
                    try {
                        await axios.delete(`/api/camera/photos/${encodeURIComponent(this.currentPhotoPath)}`);
                        this.message = '照片已删除';
                        this.messageType = 'success';
                        this.closePreview();
                    } catch (error) {
                        this.error = '删除照片失败: ' + error.message;
                    }
                },
                
                toggleDetection() {
                    this.isDetecting = !this.isDetecting;
                    if (this.isRunning) {
                        this.startFrameUpdate(); // 重新启动帧更新
                    }
                },

                async switchCamera() {
                    try {
                        // 先停止当前摄像头
                        const video = document.getElementById('videoElement');
                        if (video.srcObject) {
                            const tracks = video.srcObject.getTracks();
                            tracks.forEach(track => track.stop());
                        }

                        // 切换摄像头方向
                        this.currentFacingMode = this.currentFacingMode === 'environment' ? 'user' : 'environment';

                        // 使用新的约束
                        const constraints = {
                            video: {
                                facingMode: this.currentFacingMode,
                                width: { ideal: 1280 },
                                height: { ideal: 720 }
                            }
                        };

                        const stream = await navigator.mediaDevices.getUserMedia(constraints);

                        // 设置视频属性
                        video.setAttribute('playsinline', true);
                        video.setAttribute('autoplay', true);
                        video.setAttribute('muted', true);
                        video.srcObject = stream;

                        // 等待视频加载
                        await new Promise((resolve) => {
                            video.onloadedmetadata = () => {
                                resolve();
                            };
                        });
                        
                        await video.play();

                    } catch (error) {
                        this.error = `切换摄像头失败: ${error.message}`;
                        // 如果切换失败，尝试回退到之前的摄像头
                        this.currentFacingMode = this.currentFacingMode === 'environment' ? 'user' : 'environment';
                        try {
                            await this.startCamera();
                        } catch (e) {
                            this.error = `恢复摄像头失败: ${e.message}`;
                        }
                    }
                }
            },
            mounted() {
                this.checkStatus();
            },
            beforeDestroy() {
                this.stopFrameUpdate();
            }
        });
    </script>
</body>
</html> 